package gobelinmaker.server;

import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.imageio.ImageIO;

/**
 * Tényleges kameraképet kezelő kamera osztálya.
 *
 * @author imruf84
 */
public class GobelinRealCamera extends GobelinCamera {

    /**
     * Szerver kamera.
     */
    private final ServerCamera sc;
    /**
     * Eszköz sorszáma.
     */
    private final int deviceID;
    /**
     * Egyszerre csak egy kamerával operálunk.
     */
    private static final AtomicBoolean cameraLock = new AtomicBoolean(false);
    /**
     * Képkészítő szkript neve.
     */
    public static String webcamCaptureScriptFileName = "webcam_focus.sh";

    /**
     * Konstruktor.
     *
     * @param gs szerver
     * @param deviceID eszköz sorszáma
     * @param sc szerverkamera
     * @throws java.lang.Exception kivétel
     */
    public GobelinRealCamera(GobelinServer gs, int deviceID, ServerCamera sc) throws Exception {
        super(gs);

        this.deviceID = deviceID;
        this.sc = sc;
    }

    /**
     * Webkamera képet készítő szkript fájl nevének a lekérdezése.
     *
     * @return fájlnév
     * @throws Exception kivétel
     */
    public static String getWebcamCaptureScriptFileName() throws Exception {
        return JarPath.getJarContainingFolder(GobelinServer.class) + "/" + GobelinRealCamera.webcamCaptureScriptFileName;
    }

    /**
     * Fókuszálható kamera képeinek a készítésének a szkriptjének a létrehozása.
     *
     * @throws java.io.FileNotFoundException kivétel
     * @throws java.io.UnsupportedEncodingException kivétel
     */
    public static void createShellScriptFileForCaptureFocusedImages() throws FileNotFoundException, UnsupportedEncodingException, Exception {
        String fn = getWebcamCaptureScriptFileName();

        try (PrintWriter writer = new PrintWriter(fn, "UTF-8")) {
            writer.println("#!/bin/bash");
            writer.println("v4l2-ctl -d $1 -c focus_auto=0 | v4l2-ctl -d $1 -c focus_absolute=0");
            writer.println("v4l2-ctl -d $1 -c focus_auto=0 | v4l2-ctl -d $1 -c focus_absolute=$3");
            writer.println("fswebcam --no-banner -q -r $2 -d v4l2:/dev/video$1 --save " + JarPath.getJarContainingFolder(GobelinServer.class) + "/webcam_images/image$1.jpg");
            writer.close();

            // Jogok beállítása.
            Process p = Runtime.getRuntime().exec("chmod +x " + fn);
            p.waitFor();
        }
    }

    @Override
    public void close() {
    }

    @Override
    public BufferedImage getImage() {

        synchronized (GobelinRealCamera.cameraLock) {

            BufferedImage image = null;

            GobelinRealCamera.cameraLock.set(true);

            try {
                // Fókusztávolság beállítása ha szükséges.
                // HACK: - valamiért le kell nullázni a fókuszt, aztán újra megadni hogy a készülő kép éles legyen, amit csak shell szkript meghívásával lehet, különben minden második kép életlen marad
                Dimension resoultion = sc.getResolution();
                float focus = sc.getFocus();
                if (!(0 > focus)) {

                    ProcessBuilder pb = new ProcessBuilder(getWebcamCaptureScriptFileName(), getDeviceID() + "", (int) resoultion.getWidth() + "x" + (int) resoultion.getHeight(), (int) focus + "");
                    Process p = pb.start();
                    p.waitFor();

                    image = ImageIO.read(new File(JarPath.getJarContainingFolder(GobelinServer.class) + "/webcam_images/image" + getDeviceID() + ".jpg"));

                } else {
                    Process p = Runtime.getRuntime().exec("fswebcam -q --no-banner -p YUYV -d v4l2:/dev/video" + getDeviceID() + " -r " + (int) resoultion.getWidth() + "x" + (int) resoultion.getHeight() + " - ");
                    image = ImageIO.read(p.getInputStream());
                }
            } catch (IOException | InterruptedException ex) {
                System.err.println(ex.getLocalizedMessage());
            } catch (Exception ex) {
                System.err.println(ex.getLocalizedMessage());
            }

            GobelinRealCamera.cameraLock.set(false);

            return image;

        }

    }

    /**
     * Eszköz sorszámának a lekérdezése.
     *
     * @return eszköz sorszáma
     */
    public int getDeviceID() {
        return deviceID;
    }

}
